using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace FlashPay.Admin
{
    using FlashPay.EF;

    using AutoMapper;

    using FlashPay.Util;
    using FlashPay.Util.StatusCode;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Linq;

    using FlashPay.EF.Models;
    using HttpLogLibrary.Extensions;
    using Microsoft.AspNetCore.Http.Extensions;
    using FlashPay.Admin.Controllers;

    using Demo.Entity.Config;
    using FlashPay.Entity.Config;
    using FlashPay.Entity.Response.User;
    using FlashPay.ORM;

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {

            services.AddTransient<FlashPayContext>();

            //业务层注册服务
            foreach (var item in GetClassName("FlashPay.Service"))
            {
                foreach (var typeArray in item.Value)
                {
                    services.AddScoped(typeArray, item.Key);
                }
            }
            //数据层注册服务
            foreach (var item in GetClassName("FlashPay.DAO"))
            {
                foreach (var typeArray in item.Value)
                {
                    services.AddScoped(typeArray, item.Key);
                }
            }
            /* 系統狀態碼 */
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddScoped<StatusCodeFactory>(sp =>
            {
                String i18n = sp.GetRequiredService<IHttpContextAccessor>().HttpContext.Request.Headers["i18n"];
                if (i18n == null)
                {
                    return new StatusCodeFactoryCN();
                }

                switch (i18n.ToLower())
                {
                    case "en":
                        return new StatusCodeFactoryEN();
                }

                return new StatusCodeFactoryCN();
            });

            services.AddScoped<DbContext, FlashPayContext>();

            var memoryCache = new MemoryCacheUtil();

            services.AddScoped<MemoryCacheUtil>(_ =>
            {
                return memoryCache;
            });
            //票据
            var authenticate = new AuthenticateImpl<TicketResponse>(memoryCache);

            services.AddScoped<IAuthenticate<TicketResponse>>(sp =>{
                return authenticate;
            });

            //谷歌验证
            services.AddScoped<Util.GoogleAuthenticator.TwoFactorAuthenticator>();
            //
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            //日志
            services.AddScoped<LogRecord>(sp =>
            {
                var ticketResponse = sp.GetRequiredService<IAuthenticate<TicketResponse>>();

                var logRecord = new LogRecord();
                if (ticketResponse.data != null)
                {
                    logRecord.CompanyId = ticketResponse.data.CompanyID;
                    logRecord.CreateName = ticketResponse.data.UserName;
                    logRecord.CreateUid = ticketResponse.data.UserID;
                }

                var http = sp.GetRequiredService<IHttpContextAccessor>();
                if (http != null)
                {
                    logRecord.RequestUrl = http.HttpContext.Request.GetDisplayUrl();
                    logRecord.Ip = http.HttpContext.GetUserIp();
                }

                return logRecord;
            });

            services.Configure<CookiePolicyOptions>(options =>
            {
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
            //添加对AutoMapper的支持
            services.AddAutoMapper();
            services.AddMvc(config =>
            {
                config.Filters.Add<HttpGlobalExceptionFilter>();
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            //加载配置文件
            services.Configure<UploadConfig>(Configuration.GetSection("UploadConfig"));
            //加载配置文件
            services.Configure<PlatformConfig>(Configuration.GetSection("PlatformConfig"));
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                                   ForwardedHeaders.XForwardedProto
            });

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            //app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Default}/{action=Index}/{id?}");
            });
        }

        /// <summary>  
        /// 获取程序集中的实现类对应的多个接口
        /// </summary>  
        /// <param name="assemblyName">程序集</param>
        public Dictionary<Type, Type[]> GetClassName(string assemblyName)
        {
            if (!String.IsNullOrEmpty(assemblyName))
            {
                Assembly assembly = Assembly.Load(assemblyName);
                List<Type> ts = assembly.GetTypes().ToList();

                var result = new Dictionary<Type, Type[]>();
                foreach (var item in ts.Where(s => !s.IsInterface))
                {
                    var interfaceType = item.GetInterfaces();
                    result.Add(item, interfaceType);
                }
                return result;
            }
            return new Dictionary<Type, Type[]>();
        }
    }
}
